#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Token失效交互体验优化 - 快速修复脚本
自动应用优化修改，解决token失效后多个提示框和刷新页面体验差的问题
"""

import os
import re
import shutil
from datetime import datetime

def backup_file(file_path):
    """备份文件"""
    if os.path.exists(file_path):
        backup_path = f"{file_path}.backup.{datetime.now().strftime('%Y%m%d_%H%M%S')}"
        shutil.copy2(file_path, backup_path)
        print(f"✅ 已备份: {backup_path}")
        return backup_path
    return None

def fix_router_index():
    """修复路由守卫"""
    file_path = "frontend/src/router/index.ts"

    if not os.path.exists(file_path):
        print(f"❌ 文件不存在: {file_path}")
        return False

    backup_file(file_path)

    with open(file_path, 'r', encoding='utf-8') as f:
        content = f.read()

    # 检查是否已经修复
    if "优先验证token有效性" in content:
        print(f"⚠️  文件已修复，跳过: {file_path}")
        return True

    # 查找并替换路由守卫逻辑
    pattern = r'// 检查是否需要登录\(默认需要认证，除非明确设置为false\)\s*if \(!userStore\.token\)\s*\{[^}]+next\('/login'\)[^}]+\}\s*// 如果已登录但用户信息为空，尝试从 localStorage 恢复'

    replacement = """// 检查是否需要登录（默认需要认证，除非明确设置为false）
  if (!userStore.token) {
    // 如果已经是登录页面，直接放行，避免循环重定向
    if (to.path === '/login') {
      next()
      return
    }
    next('/login')
    return
  }

  // ✅ 新增：优先验证token有效性，避免无效token发送请求
  // 如果token存在但可能已失效，先进行验证
  try {
    const isTokenValid = await userStore.validateTokenAction()
    if (!isTokenValid) {
      // Token无效，清除本地状态并跳转到登录页
      userStore.logoutAction()
      next('/login')
      return
    }
  } catch (error) {
    // 验证token时出现错误（网络问题等），不阻断流程，继续后续逻辑
    console.warn('Token验证失败，将继续尝试加载用户信息:', error)
  }

  // 如果已登录但用户信息为空，尝试从 localStorage 恢复"""

    new_content = re.sub(pattern, replacement, content, flags=re.DOTALL)

    with open(file_path, 'w', encoding='utf-8') as f:
        f.write(new_content)

    print(f"✅ 已修复路由守卫: {file_path}")
    return True

def fix_request_ts():
    """修复请求拦截器"""
    file_path = "frontend/src/utils/request.ts"

    if not os.path.exists(file_path):
        print(f"❌ 文件不存在: {file_path}")
        return False

    backup_file(file_path)

    with open(file_path, 'r', encoding='utf-8') as f:
        content = f.read()

    # 检查是否已经修复
    if "isTokenExpired" in content:
        print(f"⚠️  文件已修复，跳过: {file_path}")
        return True

    # 1. 在文件顶部添加全局标记
    if "// 全局防抖函数" in content:
        # 在全局防抖函数前添加全局标记
        insertion_point = content.find("// 全局防抖函数")
        new_global_vars = """// 全局标记，用于防止重复显示登录过期提示
let isTokenExpired = false;
let tokenExpiredTimer: NodeJS.Timeout | null = null;

// 全局防抖函数
"""
        content = content[:insertion_point] + new_global_vars + content[insertion_point:]

    # 2. 修复响应拦截器中的401处理
    response_401_pattern = r'case 401:\s*// 处理未授权错误\s*localStorage\.removeItem\('token'\);\s*resetUserInfoRequest\(\);[^}]+return Promise\.reject\(res\);'
    response_401_replacement = """case 401:
            // 处理未授权错误
            localStorage.removeItem('token');
            resetUserInfoRequest();

            // ✅ 优化：防止重复显示提示
            if (isTokenExpired) {
              return Promise.reject(res);
            }

            isTokenExpired = true;

            // 避免在登录页面重复提示
            if (!window.location.href.includes('/login')) {
              ElMessage({
                message: '登录过期，需重新登录',
                type: 'warning',
                duration: 3000,
                onClose: () => {
                  isTokenExpired = false;
                  window.location.href = '/login';
                }
              });
            }

            // 3秒后重置标记
            if (tokenExpiredTimer) {
              clearTimeout(tokenExpiredTimer);
            }
            tokenExpiredTimer = setTimeout(() => {
              isTokenExpired = false;
            }, 3000);

            return Promise.reject(res);"""

    content = re.sub(response_401_pattern, response_401_replacement, content, flags=re.DOTALL)

    # 3. 修复错误拦截器中的401处理
    error_401_pattern = r'} else if \(is401Error\) \{[^}]+ElMessage\(\{[^}]+message: '登录过期，需重新登录',[^}]+\}\);[^}]+[^}]+\}'
    error_401_replacement = """} else if (is401Error) {
    console.error('API Authentication Error:', {
      url: error.config?.url,
      method: error.config?.method,
      status: statusCode || error.response?.status,
      statusText: error.response?.statusText,
      message: error.message || '未知错误',
      code: error.code,
      timestamp: new Date().toISOString(),
      details: '认证失败，token可能已过期或无效'
    });

    localStorage.removeItem('token');
    resetUserInfoRequest();

    // ✅ 优化：防止重复显示提示
    if (isTokenExpired) {
      return Promise.reject(error);
    }

    isTokenExpired = true;

    if (!window.location.href.includes('/login')) {
      ElMessage({
        message: '登录过期，需重新登录',
        type: 'warning',
        duration: 3000,
        onClose: () => {
          isTokenExpired = false;
          window.location.href = '/login';
        }
      });
    }

    // 3秒后重置标记
    if (tokenExpiredTimer) {
      clearTimeout(tokenExpiredTimer);
    }
    tokenExpiredTimer = setTimeout(() => {
      isTokenExpired = false;
    }, 3000);
  }"""

    # 注意：这里需要更精确的匹配，因为内容较长
    # 简化处理，手动替换关键部分
    if "} else if (is401Error)" in content:
        # 找到错误处理块并替换
        lines = content.split('\n')
        new_lines = []
        skip_until_next_else = False
        in_401_block = False

        for i, line in enumerate(lines):
            if '} else if (is401Error) {' in line:
                in_401_block = True
                new_lines.append(line)
                new_lines.append('    console.error(\'API Authentication Error:\', {')
                new_lines.append('      url: error.config?.url,')
                new_lines.append('      method: error.config?.method,')
                new_lines.append('      status: statusCode || error.response?.status,')
                new_lines.append('      statusText: error.response?.statusText,')
                new_lines.append('      message: error.message || \'未知错误\',')
                new_lines.append('      code: error.code,')
                new_lines.append('      timestamp: new Date().toISOString(),')
                new_lines.append('      details: \'认证失败，token可能已过期或无效\'')
                new_lines.append('    });')
                new_lines.append('')
                new_lines.append('    localStorage.removeItem(\'token\');')
                new_lines.append('    resetUserInfoRequest();')
                new_lines.append('')
                new_lines.append('    // ✅ 优化：防止重复显示提示')
                new_lines.append('    if (isTokenExpired) {')
                new_lines.append('      return Promise.reject(error);')
                new_lines.append('    }')
                new_lines.append('')
                new_lines.append('    isTokenExpired = true;')
                new_lines.append('')
                new_lines.append('    if (!window.location.href.includes(\'/login\')) {')
                new_lines.append('      ElMessage({')
                new_lines.append('        message: \'登录过期，需重新登录\',')
                new_lines.append('        type: \'warning\',')
                new_lines.append('        duration: 3000,')
                new_lines.append('        onClose: () => {')
                new_lines.append('          isTokenExpired = false;')
                new_lines.append('          window.location.href = \'/login\';')
                new_lines.append('        }')
                new_lines.append('      });')
                new_lines.append('    }')
                new_lines.append('')
                new_lines.append('    // 3秒后重置标记')
                new_lines.append('    if (tokenExpiredTimer) {')
                new_lines.append('      clearTimeout(tokenExpiredTimer);')
                new_lines.append('    }')
                new_lines.append('    tokenExpiredTimer = setTimeout(() => {')
                new_lines.append('      isTokenExpired = false;')
                new_lines.append('    }, 3000);')
                new_lines.append('  }')
                skip_until_next_else = True
                continue
            elif skip_until_next_else:
                if '} else if (is403Error)' in line or '} else {' in line:
                    skip_until_next_else = False
                    new_lines.append(line)
                continue
            else:
                new_lines.append(line)

        content = '\n'.join(new_lines)

    with open(file_path, 'w', encoding='utf-8') as f:
        f.write(content)

    print(f"✅ 已修复请求拦截器: {file_path}")
    return True

def main():
    print("=" * 60)
    print("🔧 Token失效交互体验优化 - 快速修复脚本")
    print("=" * 60)
    print()

    # 检查当前目录
    if not os.path.exists("frontend/src/router/index.ts"):
        print("❌ 请在项目根目录运行此脚本")
        print("   确保 frontend/src/router/index.ts 文件存在")
        return

    print("📋 修复计划:")
    print("  1. 修改路由守卫，添加token有效性检查")
    print("  2. 修改请求拦截器，防止重复显示登录过期提示")
    print()

    # 执行修复
    success = True

    try:
        print("🔄 步骤 1: 修复路由守卫...")
        if not fix_router_index():
            success = False

        print()
        print("🔄 步骤 2: 修复请求拦截器...")
        if not fix_request_ts():
            success = False

    except Exception as e:
        print(f"❌ 修复过程中出现错误: {e}")
        success = False

    print()
    print("=" * 60)
    if success:
        print("✅ 修复完成！")
        print()
        print("📝 修改摘要:")
        print("  • 路由守卫现在会在发送请求前验证token有效性")
        print("  • 当token失效时，直接跳转到登录页，避免发送无效请求")
        print("  • 请求拦截器使用全局标记防止重复显示登录过期提示")
        print("  • 多个接口同时请求时，只显示一个提示框")
        print()
        print("🚀 下一步:")
        print("  1. 重启开发服务器: npm run dev")
        print("  2. 测试token失效场景")
        print("     - 清除localStorage中的token")
        print("     - 刷新页面，确认直接跳转到登录页")
        print("     - 在页面中同时触发多个请求，确认只有一个提示框")
    else:
        print("❌ 修复失败，请检查错误信息")
    print("=" * 60)

if __name__ == "__main__":
    main()
